﻿using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Design;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;

namespace Quick.EntityFrameworkCore.Design;

public abstract class AutoDesignTimeDbContextFactoryBase<TDbContext> : IDesignTimeDbContextFactory<TDbContext>
    where TDbContext : DbContext
{
    protected virtual IHost _app { get; set; } = default!;
    protected virtual IServiceScope _scope { get; set; } = default!;

    public virtual TDbContext CreateDbContext(string[] args)
    {
        var sp = BuildDesignTimeServiceProvider(args);

        return sp.GetRequiredService<TDbContext>();
    }

    protected virtual string MigrationsAssemblyName => this.GetType().Assembly.GetName().Name!;
    protected virtual string MigrationsHistoryTableName => $"{this.GetType().Assembly.GetName().Name}__EFMigrationsHistory";

    private IServiceProvider BuildDesignTimeServiceProvider(string[] args)
    {
        var host = Host.CreateDefaultBuilder(args);

        host.ConfigureServices(ConfigureDefaultServices);
        host.ConfigureServices(ConfigureServices);
        host.ConfigureServices(ConfigureDatabaseOptions);

        _app = host.Build();
        _scope = _app.Services.CreateScope();

        return _scope.ServiceProvider;
    }

    protected virtual void ConfigureDatabaseOptions(HostBuilderContext hostContext, IServiceCollection services)
    {

    }

    protected virtual void ConfigureServices(HostBuilderContext hostContext, IServiceCollection services)
    {

    }

    private void ConfigureDefaultServices(HostBuilderContext hostContext, IServiceCollection services)
    {
        services.AddLogging(options =>
        {
            options.ClearProviders().AddConsole();
        });

        services.AddDbContext<TDbContext>(ConfigureDbContextOptions);
    }

    protected virtual void ConfigureDbContextOptions(IServiceProvider serviceProvider, DbContextOptionsBuilder builder)
        => serviceProvider.AutoConfigure<TDbContext>(builder);
}
